﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Text.RegularExpressions;
using SRF.Data.Impl;

namespace SRF.Data
{
    public class Query : IQuery
    {
        readonly char DefaultParameterToken = ':';
        readonly string ParamPattern = @"{0}[\w.]+";

        IDictionary<string, object> parameters;
        int? startRow, maxRows;
        string queryString, mode, orderBy;
        Database database;
        DbCommand command;

        public Query(string queryString, string mode,Database database)
        {
            this.queryString = queryString;
            this.mode = mode;
            this.Database = database;
            parameters = new Dictionary<string, object>();
        }

        #region 属性

        /// <summary>
        /// 
        /// </summary>
        public Database Database { get { return database; } set { database = value; } }
        /// <summary>
        /// 枚举型采用int存储
        /// </summary>
        public static bool EnumAsInt { get; set; }
        /// <summary>
        /// 当前语句（未解析的语句）
        /// </summary>
        public string QueryString { get { return queryString; } }
        public IDictionary<string, object> Parameters
        {
            get
            {
                return this.parameters;
            }
        }

        #endregion

        #region

        public System.Data.IDataReader DataReader()
        {
            BuildCommand();
            BuildPageCommand();
            return database.ExecuteReader(command);
        }
        public System.Data.DataSet DataSet()
        {
            BuildCommand();
            BuildPageCommand();
            var result = database.ExecuteDataSet(command);
            command.Connection.Close();

            return result;
        }

        public IQuery SetParameter(string paraName, object obj)
        {
            paraName = paraName.ToLower();//.Replace('.', '_');
            if (parameters.Keys.Contains(paraName) == false)
                parameters.Add(paraName, obj);
            else
                parameters[paraName] = obj;

            return this;
        }
        public IQuery SetParameter(object para)
        {
            if (para is IDictionary<string, object>)
            {
                foreach (var p in para as IDictionary<string, object>)
                {
                    SetParameter(p.Key, p.Value);
                }
            }
            else if (para is System.Collections.IDictionary)
            {
                System.Collections.IDictionary dict = para as System.Collections.IDictionary;
                foreach (var key in dict.Keys)
                {
                    SetParameter(key.ToString(), dict[key]);
                }
            }
            else
            {
                foreach (var p in para.GetType().GetProperties())
                {
                    if (EnumAsInt && p.PropertyType.IsEnum) //枚举型采用整型
                    {
                        SetParameter(p.Name, (int)p.GetValue(para, new object[0]));
                    }
                    else
                        SetParameter(p.Name, p.GetValue(para, new object[0]));
                }
            }

            return this;
        }
        public IQuery SetLimit(int startRow, int maxRows)
        {
            this.startRow = startRow;
            this.maxRows = maxRows;

            return this;
        }
        public IQuery SetOrderBy(string orderBy)
        {
            this.orderBy = orderBy;

            return this;
        }

        public int Execute()
        {
            BuildCommand();
            var result = database.ExecuteNonQuery(command);
            command.Connection.Close();

            return result;
        }
        public IList<T> List<T>()
        {
            using (System.Data.IDataReader reader = DataReader())
            {
                Mapping.IDataMapper<T> mapper = new Mapping.DataMapper<T>();
                return mapper.MapRows(reader);
            }
        }
        public bool Exists()
        {
            BuildCommand();
            var result = database.ExecuteScalar(command);
            command.Connection.Close();

            return result != null;
        }
        public object UniqueResult()
        {
            BuildCommand();
            var result = database.ExecuteScalar(command);
            command.Connection.Close();

            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T UniqueResult<T>()
        {
            using (IDataReader reader = DataReader())
            {
                Mapping.IDataMapper<T> mapper = new Mapping.DataMapper<T>();
                T result = mapper.MapRow(reader);

                return result;
            }
        }

        public IDictionary<string, object> Dictionary()
        {
            BuildCommand();
            using (IDataReader reader = DataReader())
            {
                var dict = ReadDictionary(reader);

                reader.Close();

                return dict;
            }
        }
        public IList<IDictionary<string, object>> Dictionarys()
        {
            var list = new List<IDictionary<string, object>>();
            IDictionary<string, object> dict;

            BuildCommand();

            using (IDataReader reader = DataReader())
            {
                while ((dict = ReadDictionary(reader)) != null)
                {
                    list.Add(dict);
                }

                reader.Close();
            }
            return list;
        }

        private IDictionary<string, object> ReadDictionary(IDataReader reader)
        {
            if (reader.Read())
            {
                Dictionary<string, object> dict = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
                for (int i = 0; i < reader.FieldCount; i++)
                {
                    dict.Add(reader.GetName(i), reader.GetValue(i));
                }

                return dict;
            }

            return null;
        }

        /// <summary>
        /// 获取参数值
        /// </summary>
        /// <param name="paraName"></param>
        /// <returns></returns>
        private object GetValue(string paraName)
        {
            paraName = paraName.ToLower();
            if (parameters.ContainsKey(paraName))
            {
                return parameters[paraName];
            }
            else if (defaultParameters.ContainsKey(paraName))
            {
                return defaultParameters[paraName];
            }
            else
            {
                return GetParamValue(paraName);
            }
        }

        #endregion

        #region 生成command

        /// <summary>
        /// 构建command
        /// </summary>
        void BuildCommand()
        {
            command = Database.DbProviderFactory.CreateCommand();
            command.CommandType = CommandType.Text;
            var sql = queryString.Replace(DefaultParameterToken, database.ParameterToken);
            sql = SQLParser.SQLParserFactory.Get(mode).Parse(sql, GetValue, database.ParameterToken);
            //给command参数赋值
            var paraRegex = new Regex(string.Format(ParamPattern, database.ParameterToken));
            foreach (Match paraMatch in paraRegex.Matches(sql))
            {
                var paraName = paraMatch.Value.TrimStart(database.ParameterToken).ToLower();//.Replace('.', '_');
                var cmdParaName = paraName.Replace('.', '_'); 
                if (!command.Parameters.Contains(cmdParaName))
                {
                    object value = GetValue(paraName); 
                    if (value != null)
                    {
                        DbType dbtype = database.GetDbType(value.GetType());
                        database.AddInParameter(command, cmdParaName, dbtype, value);
                    }
                    else
                    {
                        database.AddInParameter(command, cmdParaName, DbType.String, DBNull.Value); //参数值为null的情况
                    }
                }
            }
            command.CommandText = paraRegex.Replace(sql, m => m.Value.Replace('.', '_'));//把参数中的.替换成_
        }

        /// <summary>
        /// 加入分页信息
        /// </summary>
        /// <param name="command"></param>
        void BuildPageCommand()
        {
            var sql = command.CommandText;
            if (startRow != null)
                sql = database.BuildPageSql(sql, startRow.Value, maxRows, orderBy);
            command.CommandText = sql;
        }

        #endregion

        #region

        /// <summary>
        /// 默认参数
        /// </summary>
        static IDictionary<string, object> defaultParameters = new Dictionary<string, object>();

        /// <summary>
        /// 设置默认的参数
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <param name="obj">参数值</param>
        public static void AddParameter(string paraName, object obj)
        {
            paraName = paraName.ToLower();//.Replace('.', '_');
            if (defaultParameters.ContainsKey(paraName))
            {
                defaultParameters[paraName] = obj;
            }
            else
            {
                defaultParameters.Add(paraName, obj);
            }
        }
        public static void RemoveParameter(string paraName)
        {
            paraName = paraName.ToLower();//.Replace('.', '_');
            if (defaultParameters.ContainsKey(paraName))
                defaultParameters.Remove(paraName);
        }
 
        /// <summary>
        /// Query初始化时触发
        /// </summary>
        public static Func<string, object> GetParamValue;

        /// <summary>
        /// Query初始化时触发
        /// </summary>
        public static Func<string, object> GetParameter;

        #endregion

    }
}